home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / PredatorPrey / Cursors.c < prev    next >
Text File  |  1996-06-22  |  8KB  |  254 lines

  1. /* © 1988-91, Bowers Development Corp. */
  2. /* Cursors.c */
  3.  
  4. #include <Types.h>
  5. #include <Quickdraw.h>
  6. #include <Controls.h>
  7. #include <Dialogs.h>
  8. #include <Events.h>
  9. #include <Lists.h>
  10. #include <Menus.h>
  11. #include <Resources.h>
  12. #include "Globals.h"            /* for inBackground, curEvent, curWindow, cur, etc. */
  13.  
  14. #include "Cursors.h"
  15.  
  16. #include <ToolUtils.h>            /* for GetCursor, HiWord */
  17.  
  18. #pragma segment Cursors
  19.  
  20. RgnHandle            cursorRgn;
  21. CursHandle            watch;
  22.  
  23. #define kSpinTicks    15            /*1/4 of a second*/
  24. #define topLeft(r)    (((Point *) &(r))[0])
  25. #define botRight(r)    (((Point *) &(r))[1])
  26.  
  27. typedef struct
  28.     {
  29.     struct
  30.     {
  31.         unsigned short isColor    :  1;    /*TRUE ===> using color cursors (high bit)*/
  32.         unsigned short count    : 15;    /*# of cursors or “frames” in the cursor list (0-15th bits)*/
  33.     } info;
  34.     short      frame;                      /*cursor list index of the next cursor frame (0-based)*/
  35.     CursHandle hCursors [1];            /*Variable-sized list of cursor handles (0-based index)*/
  36.     } AnimCursRec, *AnimCursPtr, **AnimCursHnd;
  37.  
  38. static CursHandle    iBeam;
  39. static AnimCursHnd    shAnimCurs;            /*=> Animated cursor list*/
  40. static long            sLastTick;            /*TickCount of last SetCursor call*/
  41.  
  42. /*----------*/
  43. void LoadCursors ()
  44. {
  45.     watch = GetCursor (watchCursor);
  46.     iBeam = GetCursor (iBeamCursor);
  47.  
  48.     cursorRgn = NewRgn ();
  49.  
  50.     InitCursor ();
  51. } /*LoadCursors*/
  52.  
  53. /*----------*/
  54. static void GlobalRectRgn (RgnHandle    destRegion,
  55.                            Rect            sourceRect);
  56. static void GlobalRectRgn (RgnHandle    destRegion,
  57.                            Rect            sourceRect)
  58. {
  59.     LocalToGlobal (&topLeft (sourceRect)); 
  60.     LocalToGlobal (&botRight (sourceRect));
  61.     RectRgn (destRegion, &sourceRect);
  62. } /*GlobalRectRgn*/
  63.  
  64. /*----------*/
  65. void ShapeCursor ()
  66. {
  67.     WindowPtr        front;
  68.     WindowPeek        frontPeek;
  69.     Point            mousePoint;
  70.     RgnHandle        arrowRgn;
  71.     RgnHandle        iBeamRgn;
  72.     Rect            textRect;
  73.     RgnHandle        contentRgn;
  74.     RgnHandle        scrollBarRgn;
  75.     Rect            scrollBarRect;
  76.     
  77.     front = FrontWindow ();
  78.     frontPeek = (WindowPeek) front;
  79.     if (inBackground) {
  80.         /*let foreground set cursor*/
  81.     } else if ((front != NULL) && (frontPeek->windowKind < 0)) {
  82.         /*let da set its own cursor*/
  83.     } else { 
  84.         arrowRgn = NewRgn ();
  85.         iBeamRgn = NewRgn ();
  86.         contentRgn = NewRgn ();
  87.         scrollBarRgn = NewRgn ();
  88.         RectRgn (arrowRgn, &qd.screenBits.bounds);
  89.         mousePoint = curEvent.where;
  90.         if (front == NULL) {
  91.             /*arrow*/
  92.         } else if (front == curWindow) {
  93.             SetPort (curWindow);    /*for local-to-global*/
  94.             GlobalRectRgn (contentRgn, qd.thePort->portRect);
  95.             if (cur->vScroll != NULL) {
  96.                 scrollBarRect = (**(cur->vScroll)).contrlRect;
  97.                 GlobalRectRgn (scrollBarRgn, scrollBarRect);
  98.                 DiffRgn (contentRgn, scrollBarRgn, contentRgn);
  99.             }
  100.             if (cur->hScroll != NULL) {
  101.                 scrollBarRect = (**(cur->hScroll)).contrlRect;
  102.                 GlobalRectRgn (scrollBarRgn, scrollBarRect);
  103.                 DiffRgn (contentRgn, scrollBarRgn, contentRgn);
  104.             }
  105.             if (cur->text != NULL) {
  106.                 textRect = (**(cur->text)).viewRect;
  107.                 GlobalRectRgn (iBeamRgn, textRect);
  108.                 SectRgn (iBeamRgn, contentRgn, iBeamRgn);
  109.             }
  110.             DiffRgn (arrowRgn, iBeamRgn, arrowRgn);
  111.         }
  112.         if (PtInRgn (mousePoint, iBeamRgn)) {
  113.             SetCursor (&(**iBeam));
  114.             CopyRgn (iBeamRgn, cursorRgn);
  115.         } else {
  116.             SetCursor (&qd.arrow);
  117.             CopyRgn (arrowRgn, cursorRgn);
  118.         }
  119.         DisposeRgn (arrowRgn);
  120.         DisposeRgn (iBeamRgn);
  121.         DisposeRgn (contentRgn);
  122.         DisposeRgn (scrollBarRgn);
  123.     }
  124. } /*ShapeCursor*/
  125.  
  126. /*----------*/
  127. /* This procedure sets up this unit so that later calls to SpinCursor will spin        */
  128. /* the 'acur' resource with id aCurID. You MUST call StartBusyCursor before calling    */
  129. /* SpinCursor, SpinBackwards, or StopBusyCursor.                                    */
  130. /*----------*/
  131. void    StartBusyCursor (short        aCurID)
  132. {
  133.     short            cursID;        /*==> One cursor's rsrc id in shAnimCurs*/
  134.     CursHandle        hCurs;        /*==> One cursor in shAnimCurs*/
  135.     unsigned short    i;            /*index into animated cursor list*/
  136.     Boolean            isColor;    /*TRUE if cursor list has color cursors, FALSE otherwise*/
  137.  
  138.     shAnimCurs = (AnimCursHnd) GetResource ('acur', aCurID);
  139.     if (shAnimCurs != NULL) {
  140.         HNoPurge ((Handle) shAnimCurs);    /*We need to make shAnimCurs non-purgeable for its life span*/
  141.         isColor = (**shAnimCurs).info.isColor;
  142. /* The cursor list is a list of CursHandles, but in the resource file the cursor list is a list    */
  143. /* of resource IDs in the upper 16 bits of the CursHandles.                                        */
  144.         for (i = 0; i < (**shAnimCurs).info.count; i++) {
  145.             cursID = (short) HiWord ( (long) (**shAnimCurs).hCursors [i]);
  146.             if (isColor) {
  147.                 hCurs = (CursHandle) GetCCursor (cursID);
  148.             } else {
  149.                 hCurs = GetCursor (cursID);
  150.             }
  151.             (**shAnimCurs).hCursors [i] = hCurs;    /*Replace the resource IDs with CursHandles*/
  152. /* If the cursor is a non-color cursor ('curS' resource); make it non-purgeable.  GetCColor        */
  153. /* returns copies of the 'crsr' resources so they are already non-purgeable.                    */
  154.             if ((!isColor) && (hCurs != NULL)) {
  155.                 HNoPurge ((Handle) hCurs);
  156.             }
  157.         } /*for*/
  158.     } /*otherwise, shAnimCurs == NULL, resource not found*/
  159.  
  160.     sLastTick = 0;
  161. } /*StartBusyCursor*/
  162.  
  163. /*----------*/
  164. /* This private procedure spins the cursor by frameInc if more than kSpinTicks ticks have gone
  165. | by since it last changed the cursor.
  166. */
  167. /*----------*/
  168. static void    SpinFrame(short        frameInc);
  169. static void    SpinFrame(short        frameInc)
  170. {
  171.     short            count;            /*count of animated cursors*/
  172.     short            frameNum;        /*index into animated cursor list*/
  173.     CursHandle        hCurs;            /*==> One cursor in shAnimCurs*/
  174.     long            ticks;
  175.  
  176.     if (shAnimCurs != NULL) {
  177.         ticks = TickCount ();
  178.         if ((ticks - sLastTick) > kSpinTicks) {
  179.             count = (**shAnimCurs).info.count;
  180. /* Enough time has elapsed since last cursor change, so change the cursor, bump the    */
  181. /* frame count and note the ticks for next time.                                    */
  182.             frameNum = (**shAnimCurs).frame % count;
  183.             hCurs = (**shAnimCurs).hCursors [frameNum];
  184.             if (hCurs != NULL) {
  185.                 if ((**shAnimCurs).info.isColor) {
  186.                     SetCCursor ((CCrsrHandle) hCurs);
  187.                 } else {
  188.                     HLock ((Handle) hCurs);
  189.                     SetCursor (&(**hCurs));
  190.                     HUnlock ((Handle) hCurs);
  191.                 }
  192.             } /*otherwise, hCurs == NULL*/
  193.  
  194.             (**shAnimCurs).frame = (frameNum + count + frameInc) % count;
  195.                                         /* if (frameInc < 0,) frameNum + frameInc        */
  196.                                         /* may be < 0, so (frameNum + frameInc) % count    */
  197.                                         /* would also be < 0.                            */
  198.                                         /* Using frameNum + count + frameInc makes this    */
  199.                                         /* less likely to happen.                        */
  200.             sLastTick = ticks;
  201.         } /*otherwise, not enough time has elapsed to change the cursor*/
  202.     } /*otherwise, shAnimCurs == NULL*/
  203. } /*SpinFrame*/
  204.  
  205. /*----------*/
  206. /* This procedure should be called as often as possible when the cursor is supposed to spin.    */
  207. /* It will spin the cursor forward one frame if more than kSpinTicks ticks have gone by since    */
  208. /* it last changed the cursor.                                                                    */
  209. /*----------*/
  210. void    SpinCursor (void)
  211. {
  212.     SpinFrame (1 /*frameInc*/);
  213. } /*SpinCursor*/
  214.  
  215. /*----------*/
  216. /* This procedure should be called as often as possible when the cursor is supposed to spin.    */
  217. /* It will spin the cursor backward one frame if more than kSpinTicks ticks have gone by since    */
  218. /* it last changed the cursor.                                                                    */
  219. /*----------*/
  220. void    SpinBackwards (void)
  221. {
  222.     SpinFrame (-1 /*frameInc*/);
  223. } /*SpinBackwards*/
  224.  
  225. /*----------*/
  226. /* This procedure does the opposite of StartBusyCursor, that is, it disposes of the spinning    */
  227. /* cursor allocated by StartBusyCursor, and sets the cursor to the standard arrow.                */
  228. /*----------*/
  229. void    StopBusyCursor (void)
  230. {    CursHandle        hCurs;        /*==> One cursor in shAnimCurs*/
  231.     unsigned short    i;            /*index into animated cursor list*/
  232.     Boolean            isColor;    /*TRUE if cursor list has color cursors, FALSE otherwise*/
  233.  
  234.     if (shAnimCurs != NULL) {
  235. /*Dispose shAnimCurs's handles*/
  236.         isColor = (**shAnimCurs).info.isColor;
  237.         for (i = 0; i < (**shAnimCurs).info.count; i++) {
  238.             hCurs = (**shAnimCurs).hCursors [i];
  239.             if (hCurs != NULL) {
  240.                 if (isColor) {
  241.                     DisposCCursor ((CCrsrHandle) hCurs);
  242.                 } else {
  243.                     HPurge ((Handle) hCurs);
  244.                 }
  245.             } /*otherwise, hCurs == NULL*/
  246.         } /*otherwise, not enough time has elapsed to change the cursor*/
  247.  
  248.         ReleaseResource ((Handle) shAnimCurs);
  249.         shAnimCurs = NULL;
  250.         sLastTick = 0;
  251.     } /*otherwise, shAnimCurs == NULL*/
  252.     InitCursor ();
  253. } /*StopBusyCursor*/
  254.